package genericity;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 泛型类
 * 泛型的本质是参数化类型，也就是说所操作的数据类型被指定为一个参数。
 * 好处:
 *    1.避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型
 *    2.把运行期异常(代码运行之后会抛出的异常),提升到了编译期(写代码的时候会报错)
 * 弊端:
 *    泛型是什么类型,只能存储什么类型的数据
 */
public class GenericClass<T> {   //泛型类

    private T mContent; // 定义泛型变量

    public GenericClass(T content) {
        mContent = content;
    }


    public T getContent() {
        return mContent;
    }

    public void setContent(T content) {
        mContent = content;
    }

    /**
     * 如果所在的类不是泛型类,要需要自己声明类型
     * 泛型方法,泛型参数类型声明必须在返回类型之前
     * 定义规则: 访问权限 +<泛型标示>+泛型标示 方法名称（泛型标示 参数名称）
     */
    public <E> E show(E e) {
        return e;
    }

    public <E> void show1(E e) {
        System.out.println(e);
    }

    public <E> Set<E> union(Set<E> s1, Set<E> s2) {
        Set<E> result = new HashSet<>(s1);
        result.addAll(s2);
        return result;
    }

    public static<W> void print(W w) {		//静态方法必须声明自己的泛型,同名也和类泛型不一样
        System.out.println(w);
    }

    /**
     * 泛型接口
     *
     * @param <D>
     */
    public interface GenericInterface<D> {  // 在接口上定义泛型

        D GetVar();   // 定义抽象方法，抽象方法的返回值就是泛型类型

        void doSomething(D t);

        void doToSomething(String name);
    }



    /**
     * 泛型通配符 < ?>
     * ? 表示任意类型,如果没有明确,那么就是Object以及任意Java类;
     * 但是 ? 有比 Object 稍微高级的用法,就是能缩小一个不确定的范围,利用类似"? extends Test",意味着只接收接收Test类的子类;
     */
    private void swap(List<?> list, int i, int j) {
        swapInternal(list, i, j);
    }

    private <E> void swapInternal(List<E> list, int i, int j) {
        list.set(i, list.set(j, list.get(i)));
    }



}


